home *** CD-ROM | disk | FTP | other *** search
/ Workbench Add-On / Workbench Add-On - Volume 1.iso / BBS-Archive / Dev / gcc263-src.lha / gcc-2.6.3 / fix-header.c < prev    next >
C/C++ Source or Header  |  1994-08-11  |  22KB  |  875 lines

  1. /* fix-header.c - Make C header file suitable for C++.
  2.    Copyright (C) 1993, 1994 Free Software Foundation, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by the
  6. Free Software Foundation; either version 2, or (at your option) any
  7. later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12. GNU General Public License for more details.
  13.  
  14. You should have received a copy of the GNU General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  17.  
  18. /* This program massages a system include file (such as stdio.h),
  19.    into a form more conformant with ANSI/POSIX, and more suitable for C++:
  20.  
  21.    * extern "C" { ... } braces are added (inside #ifndef __cplusplus),
  22.    if they seem to be needed.  These prevent C++ compilers from name
  23.    mangling the functions inside the braces.
  24.  
  25.    * If an old-style incomplete function declaration is seen (without
  26.    an argument list), and it is a "standard" function listed in
  27.    the file sys-protos.h (and with a non-empty argument list), then
  28.    the declaration is converted to a complete prototype by replacing
  29.    the empty parameter list with the argument lust from sys-protos.h.
  30.  
  31.    * The program can be given a list of (names of) required standard
  32.    functions (such as fclose for stdio.h).  If a reqquired function
  33.    is not seen in the input, then a prototype for it will be
  34.    written to the output.
  35.  
  36.    * If all of the non-comment code of the original file is protected
  37.    against multiple inclusion:
  38.     #ifndef FOO
  39.     #define FOO
  40.     <body of include file>
  41.     #endif
  42.    then extra matter added to the include file is placed inside the <body>.
  43.  
  44.    * If the input file is OK (nothing needs to be done);
  45.    the output file is not written (nor removed if it exists).
  46.  
  47.    There are also some special actions that are done for certain
  48.    well-known standard include files:
  49.  
  50.    * If argv[1] is "sys/stat.h", the Posix.1 macros
  51.    S_ISBLK, S_ISCHR, S_ISDIR, S_ISFIFO, S_ISLNK, S_ISREG are added if
  52.    they were missing, and the corresponding "traditional" S_IFxxx
  53.    macros were defined.
  54.  
  55.    * If argv[1] is "errno.h", errno is declared if it was missing.
  56.  
  57.    * TODO:  The input file should be read complete into memory, because:
  58.    a) it needs to be scanned twice anyway, and
  59.    b) it would be nice to allow update in place.
  60.  
  61.    Usage:
  62.     fix-header FOO.H INFILE.H OUTFILE.H REQUIRED_FUNCS <SCAN-FILE
  63.    where:
  64.    * FOO.H is the relative file name of the include file,
  65.    as it would be #include'd by a C file.  (E.g. stdio.h)
  66.    * INFILE.H is a full pathname for the input file (e.g. /usr/include/stdio.h)
  67.    * OUTFILE.H is the full pathname for where to write the output file,
  68.    if anything needs to be done.  (e.g. ./include/stdio.h)
  69.    * SCAN-FILE is the output of the scan-decls program.
  70.    * REQUIRED_FUNCS is a list of required function (e.g. fclose for stdio.h).
  71.  
  72.    Written by Per Bothner <bothner@cygnus.com>, July 1993. */
  73.  
  74. #include <stdio.h>
  75. #include <ctype.h>
  76. #include <sys/types.h>
  77. #include <sys/stat.h>
  78. #ifndef O_RDONLY
  79. #define O_RDONLY 0
  80. #endif
  81. #include "hconfig.h"
  82. #include "obstack.h"
  83. #include "scan.h"
  84.  
  85. extern sstring buf;
  86.  
  87. int verbose = 0;
  88. int partial_count = 0;
  89. #if 0
  90. /* All uses of this are ifdefed out.  This is no longer needed, because
  91.    cccp.c implicitly forces the standard include files to be treated as C.
  92.    Adding an explicit extern "C" is undesireable as it breaks the SunOS 4.x
  93.    sun4c/romvec.h file.  */
  94. int missing_extern_C_count = 0;
  95. #endif
  96. int missing_errno = 0;
  97.  
  98. #include "xsys-protos.h"
  99.  
  100. char *inf_buffer;
  101. char *inf_limit;
  102. char *inf_ptr;
  103.  
  104. /* Certain standard files get extra treatment */
  105.  
  106. enum special_file
  107. {
  108.   no_special,
  109.   errno_special,
  110.   sys_stat_special
  111. };
  112.  
  113. enum special_file special_file_handling = no_special;
  114.  
  115. /* The following are only used when handling sys/stat.h */
  116. /* They are set if the corresponding macro has been seen. */
  117. int seen_S_IFBLK = 0, seen_S_ISBLK  = 0;
  118. int seen_S_IFCHR = 0, seen_S_ISCHR  = 0;
  119. int seen_S_IFDIR = 0, seen_S_ISDIR  = 0;
  120. int seen_S_IFIFO = 0, seen_S_ISFIFO = 0;
  121. int seen_S_IFLNK = 0, seen_S_ISLNK  = 0;
  122. int seen_S_IFREG = 0, seen_S_ISREG  = 0;
  123.  
  124. /* Wrapper around free, to avoid prototype clashes. */
  125.  
  126. void
  127. xfree (ptr)
  128.      char *ptr;
  129. {
  130.   free (ptr);
  131. }
  132.  
  133. /* Avoid error if config defines abort as fancy_abort.
  134.    It's not worth "really" implementing this because ordinary
  135.    compiler users never run fix-header.  */
  136.  
  137. void
  138. fancy_abort ()
  139. {
  140.   abort ();
  141. }
  142.  
  143. #define obstack_chunk_alloc xmalloc
  144. #define obstack_chunk_free xfree
  145. struct obstack scan_file_obstack;
  146.  
  147. /* NOTE:  If you edit this, also edit gen-protos.c !! */
  148. struct fn_decl *
  149. lookup_std_proto (name)
  150.      char *name;
  151. {
  152.   int i = hash (name) % HASH_SIZE;
  153.   int i0 = i;
  154.   for (;;)
  155.     {
  156.       struct fn_decl *fn;
  157.       if (hash_tab[i] == 0)
  158.     return NULL;
  159.       fn = &std_protos[hash_tab[i]];
  160.       if (strcmp (fn->fname, name) == 0)
  161.     return fn;
  162.       i = (i+1) % HASH_SIZE;
  163.       if (i == i0)
  164.     abort ();
  165.     }
  166. }
  167.  
  168. char *inc_filename;
  169. int inc_filename_length;
  170. char *progname = "fix-header";
  171. FILE *outf;
  172. sstring line;
  173.  
  174. int lbrac_line, rbrac_line;
  175.  
  176. char **required_functions;
  177. int required_unseen_count;
  178.  
  179. void 
  180. write_lbrac ()
  181. {
  182.   
  183. #if 0
  184.   if (missing_extern_C_count + required_unseen_count > 0)
  185.     fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
  186. #endif
  187.  
  188.   if (partial_count)
  189.     {
  190.       fprintf (outf, "#ifndef _PARAMS\n");
  191.       fprintf (outf, "#if defined(__STDC__) || defined(__cplusplus)\n");
  192.       fprintf (outf, "#define _PARAMS(ARGS) ARGS\n");
  193.       fprintf (outf, "#else\n");
  194.       fprintf (outf, "#define _PARAMS(ARGS) ()\n");
  195.       fprintf (outf, "#endif\n#endif /* _PARAMS */\n");
  196.     }
  197. }
  198.  
  199. struct partial_proto
  200. {
  201.   struct partial_proto *next;
  202.   char *fname;    /* name of function */
  203.   char *rtype;    /* return type */
  204.   struct fn_decl *fn;
  205.   int line_seen;
  206. };
  207.  
  208. struct partial_proto *partial_proto_list = NULL;
  209.  
  210. struct partial_proto required_dummy_proto;
  211. #define REQUIRED(FN) ((FN)->partial == &required_dummy_proto)
  212. #define SET_REQUIRED(FN) ((FN)->partial = &required_dummy_proto)
  213. #define CLEAR_REQUIRED(FN) ((FN)->partial = 0)
  214.  
  215. void
  216. recognized_macro (fname)
  217.      char *fname;
  218. {
  219.   /* The original include file defines fname as a macro. */
  220.   struct fn_decl *fn = lookup_std_proto (fname);
  221.  
  222.   /* Since fname is a macro, don't require a prototype for it. */
  223.   if (fn && REQUIRED (fn))
  224.     {
  225.       CLEAR_REQUIRED (fn);
  226.       required_unseen_count--;
  227.     }
  228.  
  229.   switch (special_file_handling)
  230.     {
  231.     case errno_special:
  232.       if (strcmp (fname, "errno") == 0) missing_errno = 0;
  233.       break;
  234.     case sys_stat_special:
  235.       if (fname[0] == 'S' && fname[1] == '_')
  236.     {
  237.       if (strcmp (fname, "S_IFBLK") == 0) seen_S_IFBLK++;
  238.       else if (strcmp (fname, "S_ISBLK") == 0) seen_S_ISBLK++;
  239.       else if (strcmp (fname, "S_IFCHR") == 0) seen_S_IFCHR++;
  240.       else if (strcmp (fname, "S_ISCHR") == 0) seen_S_ISCHR++;
  241.       else if (strcmp (fname, "S_IFDIR") == 0) seen_S_IFDIR++;
  242.       else if (strcmp (fname, "S_ISDIR") == 0) seen_S_ISDIR++;
  243.       else if (strcmp (fname, "S_IFIFO") == 0) seen_S_IFIFO++;
  244.       else if (strcmp (fname, "S_ISFIFO") == 0) seen_S_ISFIFO++;
  245.       else if (strcmp (fname, "S_IFLNK") == 0) seen_S_IFLNK++;
  246.       else if (strcmp (fname, "S_ISLNK") == 0) seen_S_ISLNK++;
  247.       else if (strcmp (fname, "S_IFREG") == 0) seen_S_IFREG++;
  248.       else if (strcmp (fname, "S_ISREG") == 0) seen_S_ISREG++;
  249.     }
  250.     }
  251. }
  252.  
  253. void
  254. recognized_extern (name, type)
  255.      char *name;
  256.      char *type;
  257. {
  258.   switch (special_file_handling)
  259.     {
  260.     case errno_special:
  261.       if (strcmp (name, "errno") == 0) missing_errno = 0;
  262.       break;
  263.     }
  264. }
  265.  
  266. /* Called by scan_decls if it saw a function definition for a function
  267.    named FNAME, with return type RTYPE, and argument list ARGS,
  268.    in source file FILE_SEEN on line LINE_SEEN.
  269.    KIND is 'I' for an inline function;
  270.    'F' if a normal function declaration preceded by 'extern "C"'
  271.    (or nested inside 'extern "C"' braces); or
  272.    'f' for other function declarations. */
  273.  
  274. void
  275. recognized_function (fname, kind, rtype, args, file_seen, line_seen)
  276.      char *fname;
  277.      int kind; /* One of 'f' 'F' or 'I' */
  278.      char *rtype;
  279.      char *args;
  280.      char *file_seen;
  281.      int line_seen;
  282. {
  283.   struct partial_proto *partial;
  284.   int i;
  285.   struct fn_decl *fn;
  286. #if 0
  287.   if (kind == 'f')
  288.     missing_extern_C_count++;
  289. #endif
  290.  
  291.   fn = lookup_std_proto (fname);
  292.  
  293.   /* Remove the function from the list of required function. */
  294.   if (fn && REQUIRED (fn))
  295.     {
  296.       CLEAR_REQUIRED (fn);
  297.       required_unseen_count--;
  298.     }
  299.  
  300.   /* If we have a full prototype, we're done. */
  301.   if (args[0] != '\0')
  302.     return;
  303.       
  304.   if (kind == 'I')  /* don't edit inline function */
  305.     return;
  306.  
  307.   /* If the partial prototype was included from some other file,
  308.      we don't need to patch it up (in this run). */
  309.   i = strlen (file_seen);
  310.   if (i < inc_filename_length
  311.       || strcmp (inc_filename, file_seen + (i - inc_filename_length)) != 0)
  312.     return;
  313.  
  314.   if (fn == NULL)
  315.     return;
  316.   if (fn->params[0] == '\0' || strcmp (fn->params, "void") == 0)
  317.     return;
  318.  
  319.   /* We only have a partial function declaration,
  320.      so remember that we have to add a complete prototype. */
  321.   partial_count++;
  322.   partial = (struct partial_proto*)
  323.     obstack_alloc (&scan_file_obstack, sizeof (struct partial_proto));
  324.   partial->fname = obstack_alloc (&scan_file_obstack, strlen (fname) + 1);
  325.   strcpy (partial->fname, fname);
  326.   partial->rtype = obstack_alloc (&scan_file_obstack, strlen (rtype) + 1);
  327.   strcpy (partial->rtype, rtype);
  328.   partial->line_seen = line_seen;
  329.   partial->fn = fn;
  330.   fn->partial = partial;
  331.   partial->next = partial_proto_list;
  332.   partial_proto_list = partial;
  333.   if (verbose)
  334.     {
  335.       fprintf (stderr, "(%s: %s non-prototype function declaration.)\n",
  336.            inc_filename, fname);
  337.     }
  338. }
  339.  
  340. void
  341. read_scan_file (scan_file)
  342.      FILE *scan_file;
  343. {
  344.   obstack_init (&scan_file_obstack); 
  345.  
  346.   scan_decls (scan_file);
  347.  
  348.   if (required_unseen_count + partial_count + missing_errno
  349. #if 0
  350.       + missing_extern_C_count
  351. #endif      
  352.       == 0)
  353.     {
  354.       if (verbose)
  355.     fprintf (stderr, "%s: OK, nothing needs to be done.\n", inc_filename);
  356.       exit (0);
  357.     }
  358.   if (!verbose)
  359.     fprintf (stderr, "%s: fixing %s\n", progname, inc_filename);
  360.   else
  361.     {
  362.       if (required_unseen_count)
  363.     fprintf (stderr, "%s: %d missing function declarations.\n",
  364.          inc_filename, required_unseen_count);
  365.       if (partial_count)
  366.     fprintf (stderr, "%s: %d non-prototype function declarations.\n",
  367.          inc_filename, partial_count);
  368. #if 0
  369.       if (missing_extern_C_count)
  370.     fprintf (stderr,
  371.          "%s: %d declarations not protected by extern \"C\".\n",
  372.          inc_filename, missing_extern_C_count);
  373. #endif
  374.     }
  375. }
  376.  
  377. void
  378. write_rbrac ()
  379. {
  380.   struct fn_decl *fn;
  381.   char **rptr;
  382.  
  383.   if (required_unseen_count)
  384.     {
  385.       fprintf (outf,
  386.     "#if defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__)\n");
  387. #ifdef NO_IMPLICIT_EXTERN_C
  388.       fprintf (outf, "#ifdef __cplusplus\nextern \"C\" {\n#endif\n");
  389. #endif
  390.     }
  391.  
  392.   /* Now we print out prototypes for those functions that we haven't seen. */
  393.   for (rptr = required_functions; *rptr; rptr++)
  394.     {
  395.       int macro_protect = 0;
  396.  
  397.       fn = lookup_std_proto (*rptr);
  398.       if (fn == NULL || !REQUIRED (fn))
  399.     continue;
  400.  
  401.       /* In the case of memmove, protect in case the application
  402.      defines it as a macro before including the header.  */
  403.       if (!strcmp (fn->fname, "memmove")
  404.       || !strcmp (fn->fname, "vprintf")
  405.       || !strcmp (fn->fname, "vfprintf")
  406.       || !strcmp (fn->fname, "vsprintf")
  407.       || !strcmp (fn->fname, "rewinddir"))
  408.     macro_protect = 1;
  409.  
  410.       if (macro_protect)
  411.     fprintf (outf, "#ifndef %s\n", fn->fname);
  412.       fprintf (outf, "extern %s %s (%s);\n",
  413.            fn->rtype, fn->fname, fn->params);
  414.       if (macro_protect)
  415.     fprintf (outf, "#endif\n");
  416.     }
  417.   if (required_unseen_count)
  418.     {
  419. #ifdef NO_IMPLICIT_EXTERN_C
  420.       fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
  421. #endif
  422.       fprintf (outf,
  423.     "#endif /* defined(__cplusplus) || defined(__USE_FIXED_PROTOTYPES__*/\n");
  424.     }
  425.  
  426.   switch (special_file_handling)
  427.     {
  428.     case errno_special:
  429.       if (missing_errno)
  430.     fprintf (outf, "extern int errno;\n");
  431.       break;
  432.     case sys_stat_special:
  433.       if (!seen_S_ISBLK && seen_S_IFBLK)
  434.     fprintf (outf,
  435.          "#define S_ISBLK(mode) (((mode) & S_IFMT) == S_IFBLK)\n");
  436.       if (!seen_S_ISCHR && seen_S_IFCHR)
  437.     fprintf (outf,
  438.          "#define S_ISCHR(mode) (((mode) & S_IFMT) == S_IFCHR)\n");
  439.       if (!seen_S_ISDIR && seen_S_IFDIR)
  440.     fprintf (outf,
  441.          "#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)\n");
  442.       if (!seen_S_ISFIFO && seen_S_IFIFO)
  443.     fprintf (outf,
  444.          "#define S_ISFIFO(mode) (((mode) & S_IFMT) == S_IFIFO)\n");
  445.       if (!seen_S_ISLNK && seen_S_IFLNK)
  446.     fprintf (outf,
  447.          "#define S_ISLNK(mode) (((mode) & S_IFMT) == S_IFLNK)\n");
  448.       if (!seen_S_ISREG && seen_S_IFREG)
  449.     fprintf (outf,
  450.          "#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)\n");
  451.       break;
  452.     }
  453.  
  454.  
  455. #if 0
  456.   if (missing_extern_C_count + required_unseen_count > 0)
  457.     fprintf (outf, "#ifdef __cplusplus\n}\n#endif\n");
  458. #endif
  459. }
  460.  
  461. char *
  462. xstrdup (str)
  463.      char *str;
  464. {
  465.   char *copy = (char *) xmalloc (strlen (str) + 1);
  466.   strcpy (copy, str);
  467.   return copy;
  468. }
  469.  
  470. /* Returns 1 iff the file is properly protected from multiple inclusion:
  471.    #ifndef PROTECT_NAME
  472.    #define PROTECT_NAME
  473.    #endif
  474.  
  475.  */
  476.  
  477. #define INF_GET() (inf_ptr < inf_limit ? *(unsigned char*)inf_ptr++ : EOF)
  478. #define INF_UNGET(c) ((c)!=EOF && inf_ptr--)
  479.  
  480. int
  481. inf_skip_spaces (c)
  482.      int c;
  483. {
  484.   for (;;)
  485.     {
  486.       if (c == ' ' || c == '\t')
  487.     c = INF_GET ();
  488.       else if (c == '/')
  489.     {
  490.       c = INF_GET ();
  491.       if (c != '*')
  492.         {
  493.           INF_UNGET (c);
  494.           return '/';
  495.         }
  496.       c = INF_GET ();
  497.       for (;;)
  498.         {
  499.           if (c == EOF)
  500.         return EOF;
  501.           else if (c != '*')
  502.         {
  503.           if (c == '\n')
  504.             source_lineno++, lineno++;
  505.           c = INF_GET ();
  506.         }
  507.           else if ((c = INF_GET ()) == '/')
  508.         return INF_GET ();
  509.         }
  510.     }
  511.       else
  512.     break;
  513.     }
  514.   return c;
  515. }
  516.  
  517. /* Read into STR from inf_buffer upto DELIM. */
  518.  
  519. int
  520. inf_read_upto (str, delim)
  521.      sstring *str;
  522.      int delim;
  523. {
  524.   int ch;
  525.   for (;;)
  526.     {
  527.       ch = INF_GET ();
  528.       if (ch == EOF || ch == delim)
  529.     break;
  530.       SSTRING_PUT (str, ch);
  531.     }
  532.   MAKE_SSTRING_SPACE (str, 1);
  533.   *str->ptr = 0;
  534.   return ch;
  535. }
  536.  
  537. int
  538. inf_scan_ident (s, c)
  539.      register sstring *s;
  540.      int c;
  541. {
  542.   s->ptr = s->base;
  543.   if (isalpha (c) || c == '_')
  544.     {
  545.       for (;;)
  546.     {
  547.       SSTRING_PUT (s, c);
  548.       c = INF_GET ();
  549.       if (c == EOF || !(isalnum (c) || c == '_'))
  550.         break;
  551.     }
  552.     }
  553.   MAKE_SSTRING_SPACE (s, 1);
  554.   *s->ptr = 0;
  555.   return c;
  556. }
  557.  
  558. /* Returns 1 if the file is correctly protected against multiple
  559.    inclusion, setting *ifndef_line to the line number of the initial #ifndef
  560.    and setting *endif_line to the final #endif.
  561.    Otherwise return 0. */
  562.  
  563. int
  564. check_protection (ifndef_line, endif_line)
  565.      int *ifndef_line, *endif_line;
  566. {
  567.   int c;
  568.   int if_nesting = 1; /* Level of nesting of #if's */
  569.   char *protect_name = NULL; /* Identifier following initial #ifndef */
  570.   int define_seen = 0;
  571.  
  572.   /* Skip initial white space (including comments). */
  573.   for (;; lineno++)
  574.     {
  575.       c = inf_skip_spaces (' ');
  576.       if (c == EOF)
  577.     return 0;
  578.       if (c != '\n')
  579.     break;
  580.     }
  581.   if (c != '#')
  582.     return 0;
  583.   c = inf_scan_ident (&buf, inf_skip_spaces (' '));
  584.   if (SSTRING_LENGTH (&buf) == 0 || strcmp (buf.base, "ifndef") != 0)
  585.     return 0;
  586.  
  587.   /* So far so good: We've seen an initial #ifndef. */
  588.   *ifndef_line = lineno;
  589.   c = inf_scan_ident (&buf, inf_skip_spaces (c));
  590.   if (SSTRING_LENGTH (&buf) == 0 || c == EOF)
  591.     return 0;
  592.   protect_name = xstrdup (buf.base);
  593.  
  594.   INF_UNGET (c);
  595.   c = inf_read_upto (&buf, '\n');
  596.   if (c == EOF)
  597.     return 0;
  598.   lineno++;
  599.  
  600.   for (;;)
  601.     {
  602.       c = inf_skip_spaces (' ');
  603.       if (c == EOF)
  604.     return 0;
  605.       if (c == '\n')
  606.     {
  607.       lineno++;
  608.       continue;
  609.     }
  610.       if (c != '#')
  611.     goto skip_to_eol;
  612.       c = inf_scan_ident (&buf, inf_skip_spaces (' '));
  613.       if (SSTRING_LENGTH (&buf) == 0)
  614.     ;
  615.       else if (!strcmp (buf.base, "ifndef")
  616.       || !strcmp (buf.base, "ifdef") || !strcmp (buf.base, "if"))
  617.     {
  618.       if_nesting++;
  619.     }
  620.       else if (!strcmp (buf.base, "endif"))
  621.     {
  622.       if_nesting--;
  623.       if (if_nesting == 0)
  624.         break;
  625.     }
  626.       else if (!strcmp (buf.base, "else"))
  627.     {
  628.       if (if_nesting == 1)
  629.         return 0;
  630.     }
  631.       else if (!strcmp (buf.base, "define"))
  632.     {
  633.       if (if_nesting != 1)
  634.         goto skip_to_eol;
  635.       c = inf_skip_spaces (c);
  636.       c = inf_scan_ident (&buf, c);
  637.       if (buf.base[0] > 0 && strcmp (buf.base, protect_name) == 0)
  638.         define_seen = 1;
  639.     }
  640.     skip_to_eol:
  641.       for (;;)
  642.     {
  643.       if (c == '\n' || c == EOF)
  644.         break;
  645.       c = INF_GET ();
  646.     }
  647.       if (c == EOF)
  648.     return 0;
  649.       lineno++;
  650.     }
  651.  
  652.   if (!define_seen)
  653.      return 0;
  654.   *endif_line = lineno;
  655.   /* Skip final white space (including comments). */
  656.   for (;;)
  657.     {
  658.       c = inf_skip_spaces (' ');
  659.       if (c == EOF)
  660.     break;
  661.       if (c != '\n')
  662.     return 0;
  663.     }
  664.  
  665.   return 1;
  666. }
  667.  
  668. int
  669. main (argc, argv)
  670.      int argc;
  671.      char **argv;
  672. {
  673.   int inf_fd;
  674.   struct stat sbuf;
  675.   int c;
  676.   int i, done;
  677.   char *cptr, *cptr0, **pptr;
  678.   int ifndef_line;
  679.   int endif_line;
  680.   long to_read;
  681.   long int inf_size;
  682.  
  683.   if (argv[0] && argv[0][0])
  684.     {
  685.       register char *p;
  686.  
  687.       progname = 0;
  688.       for (p = argv[0]; *p; p++)
  689.         if (*p == '/')
  690.           progname = p;
  691.       progname = progname ? progname+1 : argv[0];
  692.     }
  693.  
  694.   if (argc < 4)
  695.     {
  696.       fprintf (stderr, "%s: Usage: foo.h infile.h outfile.h req_funcs <scan-file-name\n",
  697.            progname);
  698.       exit (-1);
  699.     }
  700.  
  701.   inc_filename = argv[1];
  702.   inc_filename_length = strlen (inc_filename);
  703.   if (strcmp (inc_filename, "sys/stat.h") == 0)
  704.     special_file_handling = sys_stat_special;
  705.   else if (strcmp (inc_filename, "errno.h") == 0)
  706.     special_file_handling = errno_special, missing_errno = 1;
  707.  
  708.   /* Calculate an upper bound of the number of function names in argv[4] */
  709.   for (i = 1, cptr = argv[4]; *cptr; cptr++)
  710.     if (*cptr == ' ') i++;
  711.   /* Find the list of prototypes required for this include file. */ 
  712.   required_functions = (char**)xmalloc ((i+1) * sizeof (char*));
  713.   for (cptr = argv[4], cptr0 = cptr, pptr = required_functions, done = 0; 
  714.        !done; cptr++)
  715.     {
  716.       done = *cptr == '\0';
  717.       if (*cptr == ' ' || done)
  718.     {
  719.       *cptr = '\0';
  720.       if (cptr > cptr0)
  721.         {
  722.           struct fn_decl *fn = lookup_std_proto (cptr0);
  723.           *pptr++ = cptr0;
  724.           if (fn == NULL)
  725.         fprintf (stderr, "Internal error:  No prototype for %s\n",
  726.              cptr0);
  727.           else
  728.         SET_REQUIRED (fn);
  729.         }
  730.       cptr0 = cptr + 1;
  731.     }
  732.     }
  733.   required_unseen_count = pptr - required_functions;
  734.   *pptr = 0;
  735.  
  736.   read_scan_file (stdin);
  737.  
  738.   inf_fd = open (argv[2], O_RDONLY, 0666);
  739.   if (inf_fd < 0)
  740.     {
  741.       fprintf (stderr, "%s: Cannot open '%s' for reading -",
  742.            progname, argv[2]);
  743.       perror (NULL);
  744.       exit (-1);
  745.     }
  746.   if (fstat (inf_fd, &sbuf) < 0)
  747.     {
  748.       fprintf (stderr, "%s: Cannot get size of '%s' -", progname, argv[2]);
  749.       perror (NULL);
  750.       exit (-1);
  751.     }
  752.   inf_size = sbuf.st_size;
  753.   inf_buffer = (char*) xmalloc (inf_size + 2);
  754.   inf_buffer[inf_size] = '\n';
  755.   inf_buffer[inf_size + 1] = '\0';
  756.   inf_limit = inf_buffer + inf_size;
  757.   inf_ptr = inf_buffer;
  758.  
  759.   to_read = inf_size;
  760.   while (to_read > 0)
  761.     {
  762.       long i = read (inf_fd, inf_buffer + inf_size - to_read, to_read);
  763.       if (i < 0)
  764.     {
  765.       fprintf (stderr, "%s: Failed to read '%s' -", progname, argv[2]);
  766.       perror (NULL);
  767.       exit (-1);
  768.     }
  769.       if (i == 0)
  770.     {
  771.       inf_size -= to_read;
  772.       break;
  773.     }
  774.       to_read -= i;
  775.     }
  776.  
  777.   close (inf_fd);
  778.  
  779.   /* If file doesn't end with '\n', add one. */
  780.   if (inf_limit > inf_buffer && inf_limit[-1] != '\n')
  781.     inf_limit++;
  782.  
  783.   unlink (argv[3]);
  784.   outf = fopen (argv[3], "w");
  785.   if (outf == NULL)
  786.     {
  787.       fprintf (stderr, "%s: Cannot open '%s' for writing -",
  788.            progname, argv[3]);
  789.       perror (NULL);
  790.       exit (-1);
  791.     }
  792.  
  793.   lineno = 1;
  794.  
  795.   if (check_protection (&ifndef_line, &endif_line))
  796.     {
  797. #if 0
  798.       fprintf (stderr, "#ifndef %s on line %d; #endif on line %d\n",
  799.            protect_name, ifndef_line, endif_line);
  800. #endif
  801.       lbrac_line = ifndef_line+1;
  802.       rbrac_line = endif_line;
  803.     }
  804.   else
  805.     {
  806.       lbrac_line = 1;
  807.       rbrac_line = -1;
  808.     }
  809.  
  810.   /* Reset input file. */
  811.   inf_ptr = inf_buffer;
  812.   lineno = 1;
  813.  
  814.   for (;;)
  815.     {
  816.       if (lineno == lbrac_line)
  817.     write_lbrac ();
  818.       if (lineno == rbrac_line)
  819.     write_rbrac ();
  820.       for (;;)
  821.     {
  822.       struct fn_decl *fn;
  823.       c = INF_GET ();
  824.       if (c == EOF)
  825.         break;
  826.       if (isalpha (c) || c == '_')
  827.         {
  828.           c = inf_scan_ident (&buf, c);
  829.           INF_UNGET (c);
  830.           fputs (buf.base, outf);
  831.           fn = lookup_std_proto (buf.base);
  832.           /* We only want to edit the declaration matching the one
  833.          seen by scan-decls, as there can be multiple
  834.          declarations, selected by #ifdef __STDC__ or whatever. */
  835.           if (fn && fn->partial && fn->partial->line_seen == lineno)
  836.         {
  837.           c = inf_skip_spaces (' ');
  838.           if (c == EOF)
  839.             break;
  840.           if (c == '(')
  841.             {
  842.               c = inf_skip_spaces (' ');
  843.               if (c == ')')
  844.             {
  845.               fprintf (outf, " _PARAMS((%s))", fn->params);
  846.             }
  847.               else
  848.             {
  849.               putc ('(', outf);
  850.               INF_UNGET (c);
  851.             }
  852.             }
  853.           else
  854.             fprintf (outf, " %c", c);
  855.         }
  856.         }
  857.       else
  858.         {
  859.           putc (c, outf);
  860.           if (c == '\n')
  861.         break;
  862.         }
  863.     }
  864.       if (c == EOF)
  865.     break;
  866.       lineno++;
  867.     }
  868.   if (rbrac_line < 0)
  869.     write_rbrac ();
  870.  
  871.   fclose (outf);
  872.  
  873.   return 0;
  874. }
  875.